local GameState = {}
GameState.ERROR_INVALID_FILE_CONTENTS = -1
GameState.ERROR_HASH_MISS_MATCH       = -2
GameState.ERROR_STATE_FILE_NOT_FOUND  = -3
local crypto = require(cc.PACKAGE_NAME .. ".crypto")
local json = require(cc.PACKAGE_NAME .. ".json")
local eventListener = nil
local function encode_(values,secretKey)
    local s = json.encode(values)
    local hash = crypto.md5(s..secretKey)
    local contents = json.encode({h = hash, s = s})
    return contents
end

local function decode_(fileContents,secretKey)
    local contents = fileContents
    local j = json.decode(contents)

    if type(j) ~= "table" then
        mgrs.log:printError("GameState.decode_() - invalid contents")
        return {errorCode = GameState.ERROR_INVALID_FILE_CONTENTS}
    end

    local hash,s = j.h, j.s
    local testHash = crypto.md5(s..secretKey)
    if testHash ~= hash then
        mgrs.log:printError("GameState.decode_() - hash miss match")
        return {errorCode = GameState.ERROR_HASH_MISS_MATCH}
    end

    local values = json.decode(s)
    if type(values) ~= "table" then
        mgrs.log:printError("GameState.decode_() - invalid state data")
        return {errorCode = GameState.ERROR_INVALID_FILE_CONTENTS}
    end

    return {values = values}
end

----------------------------------------

function GameState.init(eventListener_)
    if type(eventListener_) ~= "function" then
        mgrs.log:printError("GameState.init() - invalid eventListener")
        return false
    end
    eventListener = eventListener_
    return true
end

function GameState.load(filename,secretKey)
    local filename = GameState.getGameStatePath(filename)
    if not io.exists(filename) then
        --mgrs.log:printDebug("GameState.load() - file \"%s\" not found", filename)
        return eventListener({name = "load", errorCode = GameState.ERROR_STATE_FILE_NOT_FOUND ,fileName = filename})
    end

    local contents = io.readfile(filename)
    --mgrs.log:printDebug("GameState.load() - get values from \"%s\"", filename)

    local values
    local encode = false

    local d = decode_(contents,secretKey)
    if d.errorCode then
        return eventListener({name = "load", errorCode = d.errorCode,fileName = filename})
    end
    values = d.values
    encode = true
    return eventListener({
        name   = "load",
        values = values,
        encode = encode,
        time   = os.time(),
        fileName = filename
    })
end

function GameState.save(filename,newValues,secretKey)
    local values = eventListener({
        name   = "save",
        values = newValues,
        encode = true,
        fileName = filename
    })
    if type(values) ~= "table" then
        mgrs.log:printError("GameState.save() - listener return invalid data")
        return false
    end
    local filename = GameState.getGameStatePath(filename)
    local ret = io.writefile(filename, encode_(values,secretKey))
    --mgrs.log:printDebug("GameState.save() - update file \"%s\"", filename)
    return ret
end

function GameState.getGameStatePath(filename)
    return string.gsub(device.writablePath, "[\\\\/]+$", "") .. device.directorySeparator .. filename
end

return GameState
